/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package examplesocket;

import java.io.IOException;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;

/**
 *
 * @author Administrator
 */
public class Parser{
    private static final Parser INSTANCE = new Parser();
    
    Vector<String> connectedUsers;
    Vector<String> connectedIPUsers;
    Vector<User> registeredUsers;
    ConcurrentHashMap<Integer, Group> groupsMap; 
    ConcurrentHashMap<String, Stream> listaClient; 
    private Parser() {
    }
    
    public static Parser getInstance() {
        return INSTANCE;
    }
    public void parserInitializer(Vector<String> connectedUsers,Vector<String> connectedIPUsers,Vector<User> registeredUsers,ConcurrentHashMap<Integer, Group> groupsMap,ConcurrentHashMap<String, Stream> listaClient)
    {
        this.connectedUsers=connectedUsers;
        this.connectedIPUsers=connectedIPUsers;
        this.registeredUsers=registeredUsers;
        this.groupsMap=groupsMap;
        this.listaClient=listaClient;
    }
    public synchronized void decodeMessages(String message, Stream userStream)
    {
        StringTokenizer messageField = new StringTokenizer(message, " ");
        Vector<String> messageParam = new Vector();
        while(messageField.hasMoreTokens())
               messageParam.add(messageField.nextToken());
        if(messageParam.get(0).equals("AESK"))
        {
            SecretKeySpec sks=null;
            try {
                sks = new SecretKeySpec( new sun.misc.BASE64Decoder().decodeBuffer(CryptHelper.getInstance().RSADecryptLocal(messageParam.get(1))), "AES");
            } catch (IOException ex) {
                    System.err.println("Error while saving the key");
            }
            userStream.getCurrentUser().setAESKey(sks);
        }
        else if(messageParam.get(0).equals("REG"))
        {  
            String pw=null;
            pw = CryptHelper.AESDecrypt(messageParam.get(2),userStream.getCurrentUser().getAES());
            User tmpU = new User(messageParam.get(1),pw);
            Boolean isAbsent=true;
            for(int i=0;i<registeredUsers.size(); i++)
            {
                if(tmpU.getName().equals(registeredUsers.get(i).getName()))
                    isAbsent=false;
            }
            if(isAbsent)
            {
                userStream.send("+OK REG_OK");
                registeredUsers.add(tmpU);
            }
            else
            {
                userStream.send("-ERR REG_FAILED");
            }
        }
        else if(messageParam.get(0).equals("LOGIN"))
        {
            for(int i=0;i<registeredUsers.size();i++)
                System.out.println("Users" + i + ": " + registeredUsers.get(i).getName() + " " + registeredUsers.get(i).getPassword());
            String name = messageParam.get(1);
            String pw = messageParam.get(2);
            User tmpU = new User(name,pw);
            if(connectedUsers.contains(name))
                userStream.send("-ERR ALREADY_CONNECTED");
            else if(registeredUsers.indexOf(tmpU) == -1)
                userStream.send("-ERR WRONG_LOGIN_DATA");
            else if(pw.equals(registeredUsers.get(registeredUsers.indexOf(tmpU)).getPassword()))
            {
                userStream.send("+OK ");
                for(int i=0;i<connectedUsers.size();i++)
                {
                    Stream tmpS = listaClient.get(connectedIPUsers.elementAt(i));
                    tmpS.send("NOTIFYIN " + name + " " + CryptHelper.getInstance().AESEncrypt(userStream.getCurrentUser().getAES().toString(),tmpS.getCurrentUser().getAES())); //TODO Criptare la chiave in qualche modo
                }
                connectedUsers.add(name);
                connectedIPUsers.add(userStream.getSocket().getLocalSocketAddress().toString());
                userStream.getCurrentUser().setName(name);
                userStream.getCurrentUser().setPassword(pw);
            }
            else
                userStream.send("-ERR WRONG_LOGIN_DATA");
        }
        else if(messageParam.get(0).equals("LOGOUT"))
        {
                    System.out.println("I'm in LOGOUT");
                    for(int i=0; i<connectedUsers.size();i++)
                        if(connectedUsers.get(i).equals(userStream.getCurrentUser().getName()))
                            connectedUsers.remove(i);
                    userStream.send("+OK");
                    userStream.stopStream();
        }
        else if(messageParam.get(0).equals("MKGRP"))
        {
            System.out.println("I'm in MKGRP");
            Group tmp = new Group();
            int id = 0;
            for(int i=0; i<groupsMap.size()+1;i++)
                if(groupsMap.get(i) == null)
                {
                    id = i;
                    i = groupsMap.size()+1;
                }
            for(int i=1;i<messageParam.size();i++)
            {
                String tmpName = messageParam.elementAt(i);               
                Stream tmpS = listaClient.get(connectedIPUsers.elementAt(connectedUsers.indexOf(tmpName)));
                tmp.addNewMember(tmpS.getCurrentUser());
                tmpS.send("+OK " + id);
            }
        }
        else if(messageParam.get(0).equals("ADDTO"))
        {
            if(groupsMap.get(Integer.parseInt(messageParam.get(1))) != null)
            {
                Group tmpG = groupsMap.get(Integer.parseInt(messageParam.get(1)));
                String tmpString = "GRPJOIN " + messageParam.elementAt(1);
                for(int i=2;i<messageParam.size();i++)
                {
                    String tmpName = messageParam.elementAt(i);               
                    Stream tmpS = listaClient.get(connectedIPUsers.elementAt(connectedUsers.indexOf(tmpName)));
                    tmpG.addNewMember(tmpS.getCurrentUser());
                    tmpString += " " + tmpName;
                }
                for(int i=2;i<messageParam.size();i++)
                {
                    String tmpName = messageParam.elementAt(i);
                    Stream tmpS = listaClient.get(connectedIPUsers.elementAt(connectedUsers.indexOf(tmpName)));
                    tmpS.send(tmpString);
                }
                userStream.send("+OK USERS_ADDED");
            }
            else
                userStream.send("-ERR ERROR_WHILE_ADDING");
        }
        else if(messageParam.get(0).equals("LEAVEGRP"))
        {
            if(groupsMap.get(Integer.parseInt(messageParam.get(1))) != null)
            {
                Group tmpG = groupsMap.get(Integer.parseInt(messageParam.get(1)));
                if(tmpG.isAbsent(userStream.getCurrentUser().getName()))
                    userStream.send("-ERR ERROR_WHILE_ABANDONING_GROUP");
                else
                {
                    if(!tmpG.removeMember(userStream.getCurrentUser()))
                    {
                        Enumeration<String> tmpE = tmpG.listOfKey();
                        while(tmpE.hasMoreElements())
                        {
                            String tmpName = tmpE.nextElement();
                            Stream tmpS = listaClient.get(connectedIPUsers.elementAt(connectedUsers.indexOf(tmpName)));
                            tmpS.send("GRPEND " + messageParam.get(1));
                        }
                    }
                }
            }
            else
                userStream.send("-ERR ERROR_WHILE_ABANDONING_GROUP");
        }
        else if(messageParam.get(0).equals("MSG"))
        {
            if(groupsMap.get(Integer.parseInt(messageParam.get(1))) != null)
            {
                Group tmpG = groupsMap.get(Integer.parseInt(messageParam.get(1)));
                Enumeration<String> tmpE = tmpG.listOfKey();
                while(tmpE.hasMoreElements())
                {
                    String tmpName = tmpE.nextElement();
                    Stream tmpS = listaClient.get(connectedIPUsers.elementAt(connectedUsers.indexOf(tmpName)));
                    tmpS.send("NEWMSG " + messageParam.get(1) + " " + messageParam.get(2));
                }
            }
            else
                userStream.send("-ERR GROUPID_NOT_FOUND");
        }
        else if(messageParam.get(0).equals("REQLIST"))
        {
            String tmpString = "LIST " + connectedUsers.size();
            for(int i=0;i<connectedUsers.size();i++)
                tmpString += " " + connectedUsers.elementAt(i);
            userStream.send(tmpString);
        }
        else
            System.out.println(messageParam.get(0));
    }
}
